home *** CD-ROM | disk | FTP | other *** search
- /*
- * MULTI-CHANNEL MEMO DISTRIBUTION FACILITY (MMDF)
- *
- * Department of Electrical Engineering
- * University of Delaware
- * Newark, Delaware 19711
- *
- *
- * Program Channel (inbound): Pass message into MMDF
- *
- *
- * P R 2 M M _ S E N D . C
- * =======================
- *
- * pr2mm_send [-M?] [-D] [-c <channel>] [-h|-v <host>]
- * [-s <sender>] [address...]
- *
- * specify -h if host in US order, -v (for Via:) if in UK order!
- * specify -Mj if input is JNT mail file.
- * -Ms is reserved for Batch-SMTP input format (implementation coming)
- * (default mode: give recipients on command line)
- *
- * J.B.D.Pardoe
- * University of Cambridge Computer Laboratory
- * October 1985
- *
- * July 86 - Added #ifdef V4_2BSD around return(status.w_status);
- * Added #ifdef NODUP2 - ECB
- */
-
- #include <stdio.h>
- #ifdef V4_2BSD
- #include <sys/wait.h>
- #include <sys/file.h>
- #endif /* V4_2BSD */
- #include <signal.h>
- #include "util.h"
- #include "mmdf.h"
- #include "ch.h"
- #include "ap.h"
-
-
- #define EX_OK 0 /* everything successful */
- #define EX_ADDR 1 /* bad addresses */
- #define EX_MECH 2 /* more than just bad addresses */
- #define EX_FAIL 3 /* the program failed to behave */
-
- #define PR_COMM '#'
- #define PR_ERR '*'
-
- /*
- * Define SAFEFORK if you want to be ultra careful that no mail is
- * lost; we try and notify the sender or support that we couldn't
- * deliver some mail, but if we can't then the mail will disappear
- * without trace. Other problems such as invalid arguments may also
- * cause this. If you define SAFEFORK the process doing the work is
- * monitored by another so that (as long as mail can be sent to
- * support) some notification of the error is made.
- */
- #define SAFEFORK
-
-
- #define TRY(OPERATION, WHAT) { \
- int rp = OPERATION; \
- if (rp_isbad (rp)) terminate (WHAT, rp); \
- }
-
- #define invalid_address(ADR, RPLY) { \
- reportf ("address: %s\nproblem: %s\n", ADR, (RPLY)->rp_line); \
- }
-
- extern FILE *errmsg_file;
- extern long msg_start;
- extern char *mmdflogin, *supportaddr;
- extern int errno;
- extern char *ap_dmflip ();
- extern int ap_outtype;
-
- static char
- *basic[] = {"success", "partial", "temporary", "error"},
- *domain[] = {"syntax", "general", "transfer", "authentication",
- "mail", "file system", "<illegal>", "<illegal>"};
-
- int prog_debug;
- char *sender;
- char *newsubargs;
-
- char prog_mode;
-
- terminate (s, rp)
- char *s; int rp;
- {
- printf ("%cfailed to %s\n%c %s [%03o = %s: %s %o]\n",
- PR_ERR, s, PR_ERR, rp_valstr (rp), rp & 0377,
- basic[rp_gbbit (rp)], domain[rp_gcbit (rp)], rp_gsbit (rp));
- mm_end (rp);
- exit (EX_MECH);
- }
-
- /* *
- * monitoring of process which does the work
- */
-
-
- #ifdef SAFEFORK
-
- /*
- * monitor a forked process which does the work
- */
-
- char *signame (sig)
- int sig;
- {
- static char buff[24];
- #ifdef V4_2BSD
- /* I know that the following code does not work on SysVr3 since
- * libc.a doesn't have a "sys_siglist". Possibly this only works
- * on 4.[23]BSD? -- David Herron <david@ms.uky.edu>
- */
- extern char *sys_siglist[];
-
- if (sig >= 0 && sig < NSIG) {
- return (sys_siglist [sig]);
- } else {
- sprintf (buff, "unknown signal %d", sig);
- return (buff);
- }
- #else
- sprintf(buff, "Signal %d", sig);
- return(buff);
- #endif
- }
-
-
- main (argc, argv)
- int argc; char **argv;
- {
- char *divider = "-------------------------------------------------------";
- int child_pid, pp[2];
- char **argv_old = argv;
-
- mmdf_init (*argv);
-
- if (pipe (pp) != 0 || (child_pid = fork ()) == -1) {
- mopen (supportaddr, "Problems with `recvprog' program");
- mprintf ("Failed to start up mail reception program.\n");
- mprintf ("The arguments were:\n");
- while (argc-- != 0) mprintf (" %s", *argv++);
- mprintf ("\n\nThe message follows\n\%s\n", divider);
- minclude (stdin);
- exit (mclose () == 0 ? EX_MECH : EX_FAIL);
- }
-
- if (child_pid == 0) {
- #ifndef NODUP2
- dup2 (pp[1], 1);
- dup2 (pp[1], 2);
- #else
- close(1);
- dup (pp[1]);
- close(2);
- dup (pp[1]);
- #endif NODUP2
- close (pp[0]);
- child (argc, argv);
- } else {
- int rc, stopped;
- int do_msg = 0;
- #ifdef V4_2BSD /* WIFSTOPPED instead? -- DSH */
- union wait status;
- #else
- int status;
- #endif /* V4_2BSD */
-
- close (pp[1]);
-
- do {
- rc = wait (&status);
- } while (rc != child_pid && (rc != -1 || errno == EINTR));
-
- if (rc != child_pid) {
- int err = errno; /* save errno in case open changes... */
- mopen (supportaddr, "Problems with `recvprog' program");
- mprintf ("Failed to collect child's status (pid %d, rc %d, \
- error %d).\n\n", child_pid, rc, err);
- do_msg = 1;
- #ifdef WIFSTOPPED
- } else if ((stopped = WIFSTOPPED (status)) || WIFSIGNALED (status)) {
- mopen (supportaddr, "Problem with `recvprog' program");
- mprintf ("recvprog was %sed by a signal: %s\n\n",
- (stopped? "stopp":"kill"), signame (status.w_termsig));
- do_msg = 1;
- } else if (status.w_retcode != EX_OK && status.w_retcode != EX_ADDR) {
- int mech = (status.w_retcode == EX_MECH);
- #else
- } else if ((stopped = status & 0x80) || status & 0x7F) {
- mopen (supportaddr, "Problem with `recvprog' program");
- mprintf ("recvprog was %sed by a signal: %s\n",
- (stopped? "stopp":"kill"), signame (status & 0x7F));
- do_msg = 1;
- } else if ((status>>8)&0xff != EX_OK && (status>>8)&0xff != EX_ADDR) {
- int mech = ((status>>8)&0xff == EX_MECH);
- #endif /* WIFSTOPPED */
- mopen (supportaddr, (mech?
- "recvprog exited with EX_MECH":
- "recvprog exited with unexpected status"));
- if (!mech)
- mprintf ("recvprog exited with return/status 0x%x.\n\n",
- status);
- do_msg = 1;
- }
-
- if (do_msg) {
- FILE *f;
- mprintf ("The arguments were:\n");
- while (argc-- != 0) mprintf (" %s", *argv++);
-
- mprintf ("\n\nThe program said the following:\n%s\n", divider);
- f = fdopen (pp[0], "r");
- if (f == NULL)
- mprintf ("[FAILED TO OPEN PIPE]\n");
- else
- minclude (f);
-
- mprintf ("\n%s\n\nThe message follows%s:",
- divider, (fseek (stdin, 0L, 0) < 0) ?
- " (couldn't rewind the file)":"");
- mprintf ("\n%s\n", divider);
- minclude (stdin);
- exit (mclose () == 0 ? EX_MECH : EX_FAIL);
- }
-
- if (strcmp (*(argv_old+1), "-D") == 0) {
- char buff [512]; int n;
- while ((n = read (pp[0], buff, 512)) > 0) write (1, buff, n);
- }
- #ifdef WIFSTOPPED
- exit (status.w_retcode);
- #else
- exit(status);
- #endif /* WIFSTOPPED */
- }
- }
- #endif /* SAFEFORK */
-
-
- /* *
- * pass a message into MMDF
- */
-
-
- #ifdef SAFEFORK
- #define MAIN child
- #else
- #define MAIN main
- #endif /* SAFEFORK */
-
-
- #define HT_NONE 0 /* no host specified */
- #define HT_HOST 1 /* host specified by -h */
- #define HT_VIA 2 /* host specified by -v */
-
-
- MAIN (argc, argv)
- int argc; char **argv;
- {
- char *channel, *host, *arg;
- struct rp_bufstruct rply; int rply_len;
- int rp, ex = EX_OK, n, hosttype = HT_NONE;
- char buf[BUFSIZ], subargs[32];
-
- errmsg_file = NULL;
- sender = 0;
- prog_mode = '\0';
-
- #ifndef SAFEFORK
- mmdf_init (*argv);
- #endif /* SAFEFORK */
-
- TRY (mm_init (), "initialize MMDF");
- TRY (mm_sbinit (), "initialize submission");
-
- while (--argc > 0 && *(arg = *++argv) == '-') {
- char opt = *++arg;
- char **where = 0;
- switch (opt) {
- case 'D': prog_debug = 1; break;
- case 'c': where = &channel; break;
- case 's': where = &sender; break;
- case 'S': where = &newsubargs; break;
-
- case 'h':
- case 'v':
- if (hosttype != HT_NONE) {
- printf ("%chost specified twice\n", PR_ERR);
- exit (EX_MECH);
- }
- hosttype = (opt == 'h' ? HT_HOST : HT_VIA);
- where = &host; break;
-
- case 'M':
- prog_mode = *arg; break;
-
- default:
- printf ("%cunknown argument -%c\n", PR_ERR, *arg);
- exit (EX_MECH);
- }
- if (where != 0) {
- if (--argc <= 0) {
- printf ("%cno value for -%c\n", PR_ERR, *arg);
- exit (EX_MECH);
- }
- *where = *++argv;
- }
- }
-
- if (prog_mode == 'j' && argc > 0) { /* JNT mail mode */
- printf ("%c-Mj and recipients", PR_ERR);
- exit (EX_MECH);
- } else if (prog_mode == 's' && argc > 0) { /* Batch-SMTP mail mode */
- printf ("%c-Ms and recipients", PR_ERR);
- exit (EX_MECH);
- } else if (argc == 0) {
- printf ("%cno recipients\n", PR_ERR);
- exit (EX_MECH);
- }
-
- /* Set a default timeout of 30 seconds -- the rational is that
- * recvprog will normally be called from some background daemon.
- * We're trying to avoid nameserver timeouts. -- DSH
- */
- strcpy (subargs, "tmlvk30*");
- if (channel) {
- Chan *curchan;
-
- if ((curchan = ch_nm2struct (channel)) == (Chan *) NOTOK)
- err_abrt (RP_PARM, "unknown channel name '%s'", channel);
- ch_llinit(curchan);
- sprintf (buf, "%si%s*", subargs, channel);
- strcpy (subargs, buf);
- }
- if (hosttype != HT_NONE) {
- sprintf (buf, "%sh%s*", subargs,
- (hosttype == HT_VIA ? ap_dmflip (host) : host));
- strcpy (subargs, buf);
- }
- if (!sender) {
- strcat (subargs, "s");
- }
-
- if (prog_mode == 'j') {
- ex = JNTextract_recipients (&argc, &argv);
- if (ex != EX_OK) {
- if (errmsg_file != NULL) {
- errmsg_send ();
- }
- exit (ex);
- }
- } else if (prog_mode == 's') {
- /* Batch SMTP - not implemented yet */
- printf ("%cBatch SMTP not supported yet", PR_ERR);
- exit(EX_MECH);
- }
-
- #ifdef DEBUG
- if (prog_debug) {
- printf ("%csubargs: %s", PR_COMM, subargs);
- printf ("; sender %s", sender ? sender : "(unspecified)");
- printf ("; %d recipient(s)\n", argc);
- }
- #endif
-
- TRY (mm_winit ((char *) 0, subargs, sender), "initialize for message");
- TRY (mm_rrply (&rply, &rply_len), "get result of mm_winit");
-
- switch (rp_gbval (rply.rp_val))
- { /* was source acceptable? */
- case RP_BNO:
- case RP_BTNO:
- terminate(rply.rp_line, rply.rp_val);
- }
- #ifdef DEBUG
- if (prog_debug) {
- printf ("%csubmitting addresses\n", PR_COMM); fflush (stdout);
- }
- #endif
- while (argc--) {
- char *adr = *argv++;
- #ifdef DEBUG
- if (prog_debug) {
- printf ("%c %s:\t", PR_COMM, adr); fflush (stdout);
- }
- #endif /* DEBUG */
- TRY (mm_wadr ((char *) 0, adr), "write address");
- TRY (mm_rrply (&rply, &rply_len), "get result of writing address");
- #ifdef DEBUG
- if (prog_debug) {
- printf ("[%o] %s\n", rply.rp_val & 0377, rply.rp_line);
- fflush (stdout);
- }
- #endif /* DEBUG */
- switch (rp = rp_gval (rply.rp_val)) {
- case RP_AOK:
- case RP_DOK:
- break;
- case RP_USER:
- case RP_NS:
- invalid_address (adr, &rply);
- break;
- default:
- {
- char buff [512];
- sprintf (buff, "understand reply to %s:\n%c%s",
- adr, PR_ERR, rply.rp_line);
- terminate (buff, rp);
- }
- }
- }
-
- TRY (mm_waend (), "finish writing addresses");
-
- while (n = fread (buf, sizeof (char), BUFSIZ, stdin)) {
- TRY (mm_wtxt (buf, n), "write text");
- }
-
- TRY (mm_wtend (), "finish writing text");
- TRY (mm_rrply (&rply, &rply_len), "get result of submission");
-
- switch (rp = rp_gval (rply.rp_val)) {
- case RP_MOK:
- break;
-
- case RP_NDEL:
- if (errmsg_file == NULL) {
- printf ("%csubmit returned NDEL but no error message\n",
- PR_ERR);
- exit (EX_MECH);
- }
- break;
-
- default:
- if (errmsg_file != NULL) {
- printf ("%csending error message\n", PR_COMM);
- errmsg_send ();
- }
- terminate ("understand reply from submit", rp);
- break;
- }
-
- mm_sbend ();
- mm_end (RP_OK);
-
- if (errmsg_file != NULL) {
- errmsg_send ();
- ex = EX_ADDR;
- }
- exit (ex);
-
- }
-
-
- /* *
- * reading of addresses from JNT mail file header
- *
- * (Strictly we should be using the MMDF parsing routines in this
- * code, but I'm fed up trying to get the buggers to work!! This
- * works more or less...!)
- */
-
- JNTextract_recipients (argc, argv)
- int *argc; char ***argv;
- {
- struct alist {
- struct alist *ad_next;
- char ad_addr[1]; /* well, as long as we need */
- } *alist = 0;
- int naddrs = 0;
- char **pp;
-
- rewindable_msg ();
-
- for (;;) {
- int ch;
- int lit = 0; /* in a domain literal */
- int lay = 0; /* just had layout */
- enum { D_NO, D_ADR, D_END } done = D_NO;
- char buff[ADDRSIZE];
- register char *p;
- struct alist *al;
-
- p = &buff[0];
-
- while (done == D_NO) {
- enum { T_CHAR, T_SEP, T_LAY } type = T_CHAR; /* char type */
- switch (ch = getchar ()) {
- case '\\' :
- *p++ = '\\'; ch = getchar (); break;
- case '[' :
- lit = 1; break;
- case ']' :
- lit = 0; break;
- case ',' :
- if (!lit) type = T_SEP; break;
- case '\r' :
- ch = getchar ();
- if (ch == '\n') {
- type = T_LAY;
- } else {
- ungetc (ch, stdin);
- ch = '\r';
- }
- break;
- case '\n' :
- type =T_LAY; break;
- case EOF :
- reportf ("%cJNT file ended prematurely\n", PR_COMM);
- return (EX_MECH);
- default :
- break;
- }
-
- switch (type) {
- case T_SEP :
- done = D_ADR; break;
- case T_CHAR :
- *p++ = ch;
- lay = 0;
- break;
- case T_LAY :
- if (lay) done = D_END; else lay = 1;
- break;
- }
- }
-
- *p = '\0';
- al = (struct alist *) malloc (
- sizeof (*al) - sizeof ((*al).ad_addr) +
- strlen (buff) + 1);
- al->ad_next = alist; alist = al;
- strcpy (al->ad_addr, buff);
- naddrs++;
- #ifdef DEBUG
- if (prog_debug) printf ("%caddress %d: %s%s\n",
- PR_COMM, naddrs, buff, (done==D_END? " !":""));
- #endif
- if (done == D_END) break;
- }
-
- msg_start = ftell (stdin);
-
- *argc = naddrs;
- *argv = pp = (char **) malloc (naddrs * sizeof (char *));
-
- while (naddrs-- > 0) {
- *pp++ = alist->ad_addr; alist = alist->ad_next;
- }
- return (EX_OK);
- }
-
- /* *
- * report an invalid address or other problem
- */
-
-
- reportf (f, a0, a1, a2, a3, a4, a5, a6, a7)
- char *f;
- {
- #ifdef DEBUG
- if (prog_debug) {
- printf (f, a0, a1, a2, a3, a4, a5, a6, a7);
- }
- #endif
-
- if (errmsg_file == NULL) errmsg_open ();
- fprintf (errmsg_file, f, a0, a1, a2, a3, a4, a5, a6, a7);
- fprintf (errmsg_file, "\n");
- }
-
-